#include "pub_sub_common.h"

bool is_subcriber_ready() {
  try {
    FileLock lock;
    return lock.check();
  } catch (const std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    return false;
  }
}

void publisher() {
  int sock = nn_socket(AF_SP, NN_PUB);
  if (sock < 0) {
    fprintf(stderr, "Error creating publisher socket: %s\n", nn_strerror(nn_errno()));
    return;
  }
  if (nn_bind(sock, URL) < 0) {
    fprintf(stderr, "Error binding publisher socket: %s\n", nn_strerror(nn_errno()));
    nn_close(sock);
    return;
  }
  int read_buf_len{0};
  size_t sz = sizeof (read_buf_len);
  nn_getsockopt(sock, NN_SOL_SOCKET, NN_SNDBUF, &read_buf_len, &sz);
  fprintf(stdout, "### Default NN_SNDBUF size %d.\n", read_buf_len);

#if ENABLE_CHANGE_BUFSIZE
  // Set send buffer size
  nn_setsockopt(sock, NN_SOL_SOCKET, NN_SNDBUF, &BUFFER_SIZE, sizeof(BUFFER_SIZE));
  nn_getsockopt(sock, NN_SOL_SOCKET, NN_SNDBUF, &read_buf_len, &sz);
  fprintf(stdout, "### After set NN_SNDBUF size %d.\n", read_buf_len);
#endif

  fprintf(stdout, "Publisher socket bound to %s\n", URL);

  while (!is_subcriber_ready()) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  std::vector<uint8_t> large_data;
  uint32_t data_size = create_large_data(large_data);
  uint16_t crc = calculate_crc({large_data.begin() + sizeof(uint32_t) + sizeof(uint16_t), large_data.end()});
  std::memcpy(large_data.data(), &data_size, sizeof(data_size));
  std::memcpy(large_data.data() + sizeof(data_size), &crc, sizeof(crc));
  fprintf(stdout, "@@ Start to send, current time: %s\n", get_currenttime_millis().c_str());

  for (int i = 0; i < NUM_MESSAGES; ++i) {
#if DEBUG_ON
    fprintf(stdout, "Publisher prepared message %d of size %zu bytes\n", i + 1, large_data.size());
#endif
    int bytes = nn_send(sock, large_data.data(), large_data.size(), 0);
    if (bytes < 0) {
      fprintf(stderr, "Error sending message: %s\n", nn_strerror(nn_errno()));
      nn_close(sock);
      return;
    }
#if DEBUG_ON
    fprintf(stdout, "Sent message %d of size %zu bytes\n", i + 1, large_data.size());
#endif
    std::this_thread::sleep_for(std::chrono::microseconds(THROTTLE_MESSAGE_SLEEP));  // Throttle messages
  }
  fprintf(stdout, "@@ Finish send, current time: %s\n", get_currenttime_millis().c_str());
  std::this_thread::sleep_for(std::chrono::seconds(4));
  nn_close(sock);
}

int main() {
  publisher();
  fprintf(stdout, "Publisher finish send %d messages\n", NUM_MESSAGES);
  return 0;
}
